home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / ar / ar.c < prev    next >
C/C++ Source or Header  |  1990-11-12  |  60KB  |  2,479 lines

  1. /* ar.c - Archive modify and extract.
  2.    Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/cmds/ar/RCS/ar.c,v 1.6 90/11/12 11:08:45 kupfer Exp $";
  20. #endif
  21.  
  22. #include <stdio.h>
  23. #include <ar.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <string.h>
  28. #include <bstring.h>
  29. #include <assert.h>
  30.  
  31. #if !defined(A_OUT) && !defined(MACH_O)
  32. #define A_OUT
  33. #endif
  34.  
  35. #ifdef A_OUT
  36. #ifdef COFF_ENCAPSULATE
  37. #include "a.out.encap.h"
  38. #else
  39. #include <a.out.h>
  40. #endif
  41. #endif
  42.  
  43. #ifdef MACH_O
  44. #ifndef A_OUT
  45. #include <nlist.h>
  46. #endif
  47. #include <sys/loader.h>
  48. #endif
  49.  
  50. #ifdef USG
  51. #include <time.h>
  52. #include <fcntl.h>
  53. #else
  54. #include <sys/file.h>
  55. #include <sys/time.h>
  56. #endif
  57.  
  58. #ifdef    __GNUC__
  59. #define    alloca    __builtin_alloca
  60. #else
  61. # ifdef sparc
  62. #  include <alloca.h>
  63. # else
  64. char *alloca ();
  65. # endif
  66. #endif
  67.  
  68. #ifdef    USG
  69. #define    bcopy(source, dest, size)    memcpy((dest), (source), (size))
  70. #define    bcmp(a, b, size)        memcmp((a), (b), (size))
  71. #define    bzero(s, size)            memset((s), 0, (size))
  72. #endif
  73.  
  74. /* If LOCKS is defined, locking is enabled.  If LOCK_FLOCK is defined,
  75.    then BSD-style flock() is used.  Otherwise, fcntl() is used.  If
  76.    LOCKS is not defined, LOCK_FLOCK is irrelevant.
  77.  
  78.    Locking is normally disabled because fcntl hangs on the Sun
  79.    and it isn't supported properly across NFS anyway.  */
  80.  
  81. #ifdef LOCKS
  82.  
  83. /* This flag tells whether the archive was opened read-only or
  84.    read-write.  It is used for a sanity check before trying to write a
  85.    new archive.  It is also temporarily as a workaround for a Sprite
  86.    bug that requires flock() to pass in the type of lock that is being
  87.    unlocked.  */
  88.  
  89. int open_flags;                /* O_RDONLY or O_RDWRITE */
  90.  
  91. #ifndef LOCK_FLOCK
  92. /* You might need to compile with -I/usr/include/sys if your fcntl.h
  93.    isn't in /usr/include (which is where it should be according to POSIX).  */
  94. #include <fcntl.h>
  95. #endif /* LOCK_FLOCK */
  96.  
  97. void lock_a_file (), unlock_a_file ();
  98. #endif /* LOCKS */
  99.  
  100. /* This structure represents member names.  It is here to simplify 
  101.    dealing with different truncation schemes and with names that the
  102.    user specifies as paths.  Operations deal with the `stored' name,
  103.    except we maintain a mapping to the name the user gave for
  104.    reading/writing the member.   If the user didn't specify a name
  105.    that matches the `stored' name, the `given' name is NULL.  For
  106.    names provided by the user, the `stored' name is computed
  107.    immediately, so all member_name objects should have a non-null
  108.    `stored' name.  */
  109.  
  110. struct member_name {
  111.   char *given;                /* name given by the user */
  112.   char *stored;                /* name as stored in the ar header */
  113. };
  114.  
  115. #define Empty_Name(name)    ((name)->stored == NULL)
  116.  
  117. /* This structure is used internally to represent the info
  118.    on a member of an archive.  This is to make it easier to change format.  */
  119.  
  120. struct member_desc
  121.   {
  122.     /* `given' will be zero if the user didn't specifically name this
  123.        member.  The name will be empty if this member is marked for
  124.        deletion.  */
  125.     struct member_name name;
  126.  
  127.     /* The following fields are stored in the member header as decimal or octal
  128.        numerals, but in this structure they are stored as machine numbers.  */
  129.     int mode;        /* Protection mode from member header.  */
  130.     long int date;    /* Last modify date as stored in member header.  */
  131.     unsigned int size;    /* Bytes of member's data, from member header.  */
  132.     int uid, gid;    /* UID and GID fields copied from member header.  */
  133.     unsigned int offset;/* Offset in archive of the header of this member.  */
  134.     unsigned int data_offset;/* Offset of first data byte of the member.  */
  135.  
  136.     /* The next field does not describe where the member was in the
  137.        old archive, but rather where it will be in the modified archive.
  138.        It is set up by write_archive.  */
  139.     unsigned int new_offset;    /* Offset of this member in new archive */
  140.  
  141.     /* Symdef data for member.  Used only for files being inserted.  */
  142.     struct symdef *symdefs;
  143.     unsigned int nsymdefs;    /* Number of entries of symdef data.  */
  144.     unsigned int string_size;    /* Size of strings needed by symdef data.  */
  145.   };
  146.  
  147. /* Each symbol is recorded by something like this.  */
  148.  
  149. struct symdef
  150.   {
  151.     union
  152.       {
  153.     unsigned long int stringoffset;
  154.     char *name;
  155.       } s;
  156.     unsigned long int offset;
  157.   };
  158.  
  159. /* Nonzero means that it's the name of an existing member;
  160.    position new or moved files with respect to this one.  */
  161.  
  162. struct member_name *posname;
  163.  
  164.  
  165. /* How to use `posname':
  166.    POS_BEFORE means position before that member.
  167.    POS_AFTER means position after that member.
  168.    POS_DEFAULT if position by default; then `posname' should also be zero. */
  169.  
  170. enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
  171.  
  172. /* Nonzero means describe each action performed.  */
  173.  
  174. int verbose;
  175.  
  176. /* Nonzero means don't warn about creating the archive file if necessary.  */
  177.  
  178. int silent_create;
  179.  
  180. /* Nonzero means don't replace existing members whose
  181.    dates are more recent than the corresponding files.  */
  182.  
  183. int newer_only;
  184.  
  185. /* Nonzero means preserve dates of members when extracting them.  */
  186.  
  187. int preserve_dates;
  188.  
  189. /* Operation to be performed.  */
  190.  
  191. #define DELETE 1
  192. #define REPLACE 2
  193. #define PRINT_TABLE 3
  194. #define PRINT_FILES 4
  195. #define EXTRACT 5
  196. #define MOVE 6
  197. #define QUICK_APPEND 7
  198.  
  199. int operation;
  200.  
  201. /* Name of archive file.  */
  202.  
  203. char *archive;
  204.  
  205. /* Descriptor for the archive file.  This descriptor is used for
  206.    locking the archive.  -1 if the archive is not yet opened.  */
  207.  
  208. int arcfd;
  209.  
  210. /* File pointer for the archive, used only for reading the archive.  0 
  211.    if the archive hasn't been opened yet.  */
  212.  
  213. FILE *arcstream;
  214.  
  215. /* (Pointer to) an array of file names specified by the user.  The 
  216.    last element is a dummy, with an "empty" name.  The remaining
  217.    elements have both `given' and `header' filled in.  Zero if the
  218.    user didn't specify any file names.  */
  219.  
  220. struct member_name *file_args;
  221.  
  222. /* *** Lots of globals related to the __.SYMDEF member.***  */
  223.  
  224. /* Name "__.SYMDEF", converted to "member_name" form. */
  225.  
  226. struct member_name symdef_name;
  227.  
  228. /* Nonzero means write a __.SYMDEF member into the modified archive.  */
  229.  
  230. int symdef_flag;
  231.  
  232. /* Nonzero means __.SYMDEF member exists in old archive.  */
  233.  
  234. int symdef_exists;
  235.  
  236. /* Nonzero means don't update __.SYMDEF unless the flag was given.  */
  237.  
  238. int ignore_symdef;
  239.  
  240. /* Total number of symdef entries we will have. */
  241.  
  242. unsigned long int nsymdefs;
  243.  
  244. /* Symdef data from old archive (set up only if we need it) */
  245.  
  246. struct symdef *old_symdefs;
  247.  
  248. /* Number of symdefs in remaining in old_symdefs.  */
  249.  
  250. unsigned int num_old_symdefs;
  251.  
  252. /* Number of symdefs old_symdefs had when it was read in.  */
  253.  
  254. unsigned long int original_num_symdefs;
  255.  
  256. /* String table from old __.SYMDEF member.  */
  257.  
  258. char *old_strings;
  259.  
  260. /* Size of old_strings */
  261.  
  262. unsigned long int old_strings_size;
  263.  
  264. /* String table to be written into __.SYMDEF member.  */
  265.  
  266. char *new_strings;
  267.  
  268. /* Size of new_strings */
  269.  
  270. unsigned long int new_strings_size;
  271.  
  272. /* ***End of __.SYMDEF globals.*** */
  273.  
  274. /* Controls the way in which long names are truncated.  If non-zero,
  275.    SomeVeryLongName.o is converted to SomeVeryLongN.o.  Otherwise, it
  276.    is converted to SomeVeryLongNam (which is compatible with the BSD
  277.    ar).  */
  278.  
  279. #ifndef GNU_TRUNCATION
  280. #define GNU_TRUNCATION    1
  281. #endif
  282.  
  283. int gnu_truncation = GNU_TRUNCATION;
  284.  
  285. /* An archive map is a chain of these structures.
  286.   Each structure describes one member of the archive.
  287.   The chain is in the same order as the members are.  */
  288.  
  289. struct mapelt
  290.   {
  291.     struct member_desc info;
  292.     struct mapelt *next;
  293.   };
  294.  
  295. struct mapelt *maplast;
  296.  
  297. /* If nonzero, this is the map-element for the __.SYMDEF member
  298.    and we should update the time of that member just before finishing.  */
  299.  
  300. struct mapelt *symdef_mapelt;
  301.  
  302. /* Header that we wrote for the __.SYMDEF member.  */
  303.  
  304. struct ar_hdr symdef_header;
  305.  
  306. char *xmalloc (), *xrealloc ();
  307. void free ();
  308.  
  309. void add_to_map (), delete_from_map ();
  310. int insert_in_map ();
  311. void print_descr ();
  312. char *concat ();
  313. void scan ();
  314. void extract_members ();
  315. void extract_member ();
  316. void print_contents ();
  317. void write_symdef_member ();
  318. void read_old_symdefs ();
  319. void two_operations ();
  320. void usage (), fatal (), error (), error_with_file ();
  321. void perror_with_name (), pfatal_with_name ();
  322. void open_archive ();
  323. void write_archive ();
  324. void touch_symdef_member ();
  325. void update_symdefs ();
  326. void delete_members (), move_members (), replace_members ();
  327. void quick_append ();
  328. void init_elt (), mark_as_deleted ();
  329. int marked_for_deletion ();
  330. int name_match ();
  331. void init_name (), free_name_strings ();
  332. int move_in_map ();
  333. int filter_symbols ();
  334. char *user_to_header ();
  335. struct member_name *make_file_args ();
  336. void verify_is_archive ();
  337. #if DEBUG
  338. void verify_symdefs ();
  339. #endif
  340.  
  341. /* Output BYTES of data at BUF to the descriptor DESC.
  342.    FILE is the name of the file (for error messages).  */
  343.  
  344. void
  345. mywrite (desc, buf, bytes, file)
  346.      int desc;
  347.      char *buf;
  348.      int bytes;
  349.      char *file;
  350. {
  351.   register int val;
  352.  
  353.   while (bytes > 0)
  354.     {
  355.       val = write (desc, buf, bytes);
  356.       if (val <= 0)
  357.     perror_with_name (file);
  358.       buf += val;
  359.       bytes -= val;
  360.     }
  361. }
  362.  
  363. int
  364. main (argc, argv)
  365.      int argc;
  366.      char **argv;
  367. {
  368.   int i;
  369.  
  370.   operation = 0;
  371.   verbose = 0;
  372.   newer_only = 0;
  373.   silent_create = 0;
  374.   posname = 0;
  375.   postype = POS_DEFAULT;
  376.   preserve_dates = 0;
  377.   init_name (&symdef_name, "__.SYMDEF");
  378.   symdef_flag = 0;
  379.   symdef_exists = 0;
  380.   ignore_symdef = 0;
  381.   symdef_mapelt = 0;
  382.   file_args = 0;
  383.   arcfd = -1;
  384.   arcstream = 0;
  385.  
  386.   if (argc < 2)
  387.     usage ("too few command arguments", 0);
  388.  
  389.   {
  390.     char *key = argv[1];
  391.     char *p = key;
  392.     char c;
  393.  
  394.     while (c = *p++)
  395.       {
  396.     switch (c)
  397.       {
  398.       case 'a':
  399.         postype = POS_AFTER;
  400.         break;
  401.  
  402.       case 'b':
  403.         postype = POS_BEFORE;
  404.         break;
  405.  
  406.       case 'c':
  407.         silent_create = 1;
  408.         break;
  409.  
  410.       case 'd':
  411.         if (operation)
  412.           two_operations ();
  413.  
  414.         operation = DELETE;
  415.         break;
  416.  
  417.       case 'i':
  418.         postype = POS_BEFORE;
  419.         break;
  420.  
  421.       case 'l':
  422.         break;
  423.  
  424.       case 'm':
  425.         if (operation)
  426.           two_operations ();
  427.         operation = MOVE;
  428.         break;
  429.  
  430.       case 'o':
  431.         preserve_dates = 1;
  432.         break;
  433.  
  434.       case 'p':
  435.         if (operation)
  436.           two_operations ();
  437.         operation = PRINT_FILES;
  438.         break;
  439.  
  440.       case 'q':
  441.         if (operation)
  442.           two_operations ();
  443.         operation = QUICK_APPEND;
  444.         break;
  445.  
  446.       case 'r':
  447.         if (operation && operation != REPLACE)
  448.           two_operations ();
  449.         operation = REPLACE;
  450.         break;
  451.  
  452.       case 's':
  453.         symdef_flag = 1;
  454.         break;
  455.  
  456.       case 't':
  457.         if (operation)
  458.           two_operations ();
  459.         operation = PRINT_TABLE;
  460.         break;
  461.  
  462.       case 'u':
  463.         if (operation && operation != REPLACE)
  464.           two_operations ();
  465.         operation = REPLACE;
  466.         newer_only = 1;
  467.         break;
  468.  
  469.       case 'v':
  470.         verbose = 1;
  471.         break;
  472.  
  473.       case 'x':
  474.         if (operation)
  475.           two_operations ();
  476.         operation = EXTRACT;
  477.         break;
  478.       }
  479.       }
  480.   
  481.   }
  482.  
  483.   if (operation == 0 && symdef_flag)
  484.     operation = REPLACE;
  485.  
  486.   if (operation == 0)
  487.     usage ("no operation specified", 0);
  488.  
  489.   i = 2;
  490.  
  491.   if (postype != POS_DEFAULT)
  492.     posname = make_file_args(&argv[i++], 1);
  493.  
  494.   archive = argv[i++];
  495.  
  496.   if (i < argc)
  497.     {
  498.       file_args = make_file_args(&argv[i], argc - i);
  499.       while (i < argc)
  500.     if (!strcmp (argv[i++], "__.SYMDEF"))
  501.       {
  502.         ignore_symdef = 1;
  503.         break;
  504.       }
  505.     }
  506.  
  507.   switch (operation)
  508.     {
  509.     case EXTRACT:
  510.     extract_members (extract_member);
  511.     break;
  512.  
  513.     case PRINT_TABLE:
  514.     extract_members (print_descr);
  515.     break;
  516.  
  517.     case PRINT_FILES:
  518.     extract_members (print_contents);
  519.     break;
  520.  
  521.     case DELETE:
  522.     if (file_args != 0)
  523.       delete_members ();
  524.     break;
  525.  
  526.     case MOVE:
  527.     if (file_args != 0)
  528.       move_members ();
  529.     break;
  530.  
  531.     case REPLACE:
  532.     if (file_args != 0 || symdef_flag)
  533.       replace_members ();
  534.     break;
  535.  
  536.     case QUICK_APPEND:
  537.     if (file_args != 0)
  538.       quick_append ();
  539.     break;
  540.  
  541.     default:
  542.     usage ("invalid operation %d", operation);
  543.     }
  544.  
  545.   exit (0);
  546.   return 0;
  547. }
  548.  
  549. void
  550. two_operations ()
  551. {
  552.   usage ("two different operation switches specified", 0);
  553. }
  554.  
  555. /* Apply the given function to all members in the archive.  */
  556.  
  557. void
  558. scan (function, crflag)
  559.      void (*function) ();
  560.      int crflag;
  561. {
  562.   if (arcstream == 0)
  563.     open_archive (O_RDONLY);
  564.  
  565.   if (arcstream == 0 && crflag)
  566.     /* Creation-warning, if desired, will happen later.  */
  567.     return;
  568.  
  569.   if (arcstream == 0)
  570.     pfatal_with_name (archive);
  571.   verify_is_archive (arcfd);
  572.  
  573.   /* Now find the members one by one.  */
  574.   {
  575.     int member_offset = SARMAG;
  576.     while (1)
  577.       {
  578.     int nread;
  579.     struct ar_hdr member_header;
  580.     struct member_desc member_desc;
  581.     char name [1 + sizeof member_header.ar_name];
  582.  
  583.     if (fseek (arcstream, member_offset, 0) < 0)
  584.       perror_with_name (archive);
  585.  
  586.     nread = fread (&member_header, 1, sizeof (struct ar_hdr), arcstream);
  587.     if (nread == 0)
  588.       /* No data left means end of file; that is OK.  */
  589.       break;
  590.  
  591.     if (nread != sizeof (member_header)
  592.         || bcmp (member_header.ar_fmag, ARFMAG, 2))
  593.       fatal ("file %s not a valid archive", archive);
  594.     bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
  595.  
  596.     /* remove trailing blanks */
  597.     {
  598.       char *p = name + sizeof member_header.ar_name;
  599.       *p = '\0';
  600.       while (p > name && *--p == ' ')
  601.         *p = '\0';
  602.     }
  603.  
  604.     /* Make a safe copy of the name, so that `function' can just 
  605.        make a copy of `member_desc'.  */
  606.     member_desc.name.stored = concat (name, "", "");
  607.     member_desc.name.given = NULL;
  608.  
  609.     sscanf (member_header.ar_mode, "%o", &member_desc.mode);
  610.     member_desc.date = atoi (member_header.ar_date);
  611.     member_desc.size = atoi (member_header.ar_size);
  612.     member_desc.uid = atoi (member_header.ar_uid);
  613.     member_desc.gid = atoi (member_header.ar_gid);
  614.     member_desc.offset = member_offset;
  615.     member_desc.data_offset = member_offset + sizeof (member_header);
  616.  
  617.     member_desc.new_offset = 0;
  618.     member_desc.symdefs = 0;
  619.     member_desc.nsymdefs = 0;
  620.     member_desc.string_size = 0;
  621.  
  622.     if (!ignore_symdef && !strcmp (name, "__.SYMDEF"))
  623.       symdef_exists = 1;
  624.  
  625.     function (member_desc, arcstream);
  626.  
  627.     member_offset += sizeof (member_header) + member_desc.size;
  628.     if (member_offset & 1)
  629.       ++member_offset;
  630.       }
  631.   }
  632. }
  633.  
  634. void print_modes ();
  635.  
  636. void
  637. print_descr (member)
  638.      struct member_desc member;
  639. {
  640.   char *timestring;
  641.   if (!verbose)
  642.     {
  643.       puts (member.name.stored);
  644.       return;
  645.     }
  646.   print_modes (member.mode);
  647.   timestring = ctime (&member.date);
  648.   printf (" %2d/%2d %6d %12.12s %4.4s %s\n",
  649.       member.uid, member.gid,
  650.       member.size, timestring + 4, timestring + 20,
  651.       member.name.stored);
  652. }
  653.  
  654. void
  655. print_modes (modes)
  656.      int modes;
  657. {
  658.   putchar (modes & 0400 ? 'r' : '-');
  659.   putchar (modes & 0200 ? 'w' : '-');
  660.   putchar (modes & 0100 ? 'x' : '-');
  661.   putchar (modes & 040 ? 'r' : '-');
  662.   putchar (modes & 020 ? 'w' : '-');
  663.   putchar (modes & 010 ? 'x' : '-');
  664.   putchar (modes & 04 ? 'r' : '-');
  665.   putchar (modes & 02 ? 'w' : '-');
  666.   putchar (modes & 01 ? 'x' : '-');
  667. }
  668.  
  669. #define BUFSIZE 1024
  670.  
  671. void
  672. extract_member (member, istream)
  673.      struct member_desc member;
  674.      FILE *istream;
  675. {
  676.   int ncopied = 0;
  677.   FILE *ostream;
  678.   char *filename;            /* name to store file into */
  679.  
  680.   fseek (istream, member.data_offset, 0);
  681.   filename = (member.name.given ? member.name.given : member.name.stored);
  682.   ostream = fopen (filename, "w");
  683.   if (!ostream)
  684.     {
  685.       perror_with_name (filename);
  686.       return;
  687.     }
  688.  
  689.   if (verbose)
  690.     printf ("x - %s\n", filename);
  691.  
  692.   while (ncopied < member.size)
  693.     {
  694.       char buf [BUFSIZE];
  695.       int tocopy = member.size - ncopied;
  696.       int nread;
  697.       if (tocopy > BUFSIZE) tocopy = BUFSIZE;
  698.       nread = fread (buf, 1, tocopy, istream);
  699.       if (nread != tocopy)
  700.     fatal ("file %s not a valid archive", archive);
  701.       fwrite (buf, 1, nread, ostream);
  702.       ncopied += tocopy;
  703.     }
  704.  
  705. #ifdef USG
  706.   chmod (filename, member.mode);
  707. #else
  708.   fchmod (fileno (ostream), member.mode);
  709. #endif
  710.   if (ferror (ostream) || fclose (ostream) != 0)
  711.     error ("%s: I/O error", filename);
  712.  
  713.   if (preserve_dates)
  714.     {
  715. #ifdef USG
  716.       long tv[2];
  717.       tv[0] = member.date;
  718.       tv[1] = member.date;
  719.       utime (filename, tv);
  720. #else
  721.       struct timeval tv[2];
  722.       tv[0].tv_sec = member.date;
  723.       tv[0].tv_usec = 0;
  724.       tv[1].tv_sec = member.date;
  725.       tv[1].tv_usec = 0;
  726.       utimes (filename, tv);
  727. #endif
  728.     }
  729. }
  730.  
  731. void
  732. print_contents (member, istream)
  733.      struct member_desc member;
  734.      FILE *istream;
  735. {
  736.   int ncopied = 0;
  737.  
  738.   fseek (istream, member.data_offset, 0);
  739.  
  740.   if (verbose)
  741.     printf ("\n<member %s>\n\n", member.name.stored);
  742.  
  743.   while (ncopied < member.size)
  744.     {
  745.       char buf [BUFSIZE];
  746.       int tocopy = member.size - ncopied;
  747.       int nread;
  748.       if (tocopy > BUFSIZE) tocopy = BUFSIZE;
  749.       nread = fread (buf, 1, tocopy, istream);
  750.       if (nread != tocopy)
  751.     fatal ("file %s not a valid archive", archive);
  752.       fwrite (buf, 1, nread, stdout);
  753.       ncopied += tocopy;
  754.     }
  755. }
  756.  
  757. /* Make a map of the existing members of the archive: their names,
  758.  positions and sizes.  */
  759.  
  760. /* If `nonexistent_ok' is nonzero,
  761.  just return 0 for an archive that does not exist.
  762.  This will cause the ordinary supersede procedure to
  763.  create a new archive.  */
  764.  
  765. struct mapelt *
  766. make_map (nonexistent_ok)
  767.      int nonexistent_ok;
  768. {
  769.   struct mapelt mapstart;
  770.   mapstart.next = 0;
  771.   maplast = &mapstart;
  772.   scan (add_to_map, nonexistent_ok);
  773.   return mapstart.next;
  774. }
  775.  
  776. void
  777. add_to_map (member)
  778.      struct member_desc member;
  779. {
  780.   struct mapelt *mapelt = (struct mapelt *) xmalloc (sizeof (struct mapelt));
  781.  
  782.   mapelt->info = member;
  783.   maplast->next = mapelt;
  784.   mapelt->next = 0;
  785.   maplast = mapelt;
  786. }
  787.  
  788. /* Return the last element of the specified map.  */
  789.  
  790. struct mapelt *
  791. last_mapelt (map)
  792.      struct mapelt *map;
  793. {
  794.   struct mapelt *tail = map;
  795.   while (tail->next) tail = tail->next;
  796.   return tail;
  797. }
  798.  
  799. /* Return the element of the specified map which precedes elt.  */
  800.  
  801. struct mapelt *
  802. prev_mapelt (map, elt)
  803.      struct mapelt *map, *elt;
  804. {
  805.   struct mapelt *tail = map;
  806.   while (tail->next && tail->next != elt)
  807.     tail = tail->next;
  808.   if (tail->next) return tail;
  809.   return 0;
  810. }
  811.  
  812. /* Return the element of the specified map which has the specified 
  813.    name.  Possible side effect: if NAME or the matching element has a
  814.    known `given' (user) name, that name is propagated so that both
  815.    NAME and the matching element have it.  */
  816.  
  817. struct mapelt *
  818. find_mapelt_noerror (map, name)
  819.      struct mapelt *map;
  820.      struct member_name *name;
  821. {
  822.   register struct mapelt *tail;
  823.  
  824.   for (tail = map; tail != 0; tail = tail->next)
  825.     {
  826.       if (marked_for_deletion (tail))
  827.     continue;
  828.       if (name_match (&tail->info.name, name))
  829.     return tail;
  830.     }
  831.  
  832.   return 0;
  833. }
  834.  
  835. struct mapelt *
  836. find_mapelt (map, name)
  837.      struct mapelt *map;
  838.      struct member_name *name;
  839. {
  840.   register struct mapelt *found = find_mapelt_noerror (map, name);
  841.   if (found == 0)
  842.     error ("no member named `%s'", name->stored);
  843.   return found;
  844. }
  845.  
  846. /* Open the archive, either read-only or read-write, using the global
  847.    name "archive".  The archive is locked at this time to protect
  848.    against a concurrent writer.  This lock will be released when the
  849.    archive is closed.  This routine should only be called once--no
  850.    upgrading of access from read-only to read-write is allowed.
  851.  
  852.    Side effects:
  853.    - If opening read-write and the archive doesn't exist, create it.
  854.    - arcfd and arctream are set to mean the opened archive.  If the
  855.      archive doesn't exist and can't be created, they are left as
  856.      meaning "unopened".  */
  857.  
  858. void
  859. open_archive (how)
  860.      int how;                /* O_RDONLY or O_RDWR */
  861. {
  862.   void open_for_reading (), open_for_update ();
  863.   if (arcfd != -1 || arcstream != 0)
  864.     fatal ("opening archive twice");
  865.  
  866.   switch (how)
  867.     {
  868.     case O_RDONLY:
  869.       open_for_reading ();
  870.       break;
  871.     case O_RDWR:
  872.       open_for_update ();
  873.       break;
  874.     default:
  875.       fatal ("bogus flag passed to open_archive");
  876.     }
  877. }
  878.  
  879. /* Open the archive for read-only access.  If the archive doesn't
  880.    exist, just quit.  */
  881.  
  882. void
  883. open_for_reading ()
  884. {
  885.   arcfd = open (archive, O_RDONLY, 0);
  886.   if (arcfd < 0 && errno != ENOENT)
  887.     pfatal_with_name (archive);
  888.   if (arcfd < 0)
  889.     return;
  890.  
  891.   lock_a_file (arcfd, O_RDONLY);
  892.  
  893.   arcstream = fdopen (arcfd, "r");
  894.   if (arcstream == 0)
  895.     fatal ("can't make stream for archive");
  896. }
  897.  
  898. /* Open the archive for read-write access.  If it doesn't exist,
  899.    create it.  The order of creates and opens and locks is to keep
  900.    competing ar's (spawned by pmake) from tripping on each other.  */
  901.  
  902. void
  903. open_for_update ()
  904. {
  905.   struct stat statbuf;
  906.  
  907.   /* Assume that the archive doesn't exist, and try to create it.  If 
  908.      it does exist, just open it normally.  */
  909.   arcfd = open (archive, O_RDWR | O_CREAT | O_EXCL, 0666);
  910.   if (arcfd < 0 && errno != EEXIST)
  911.     pfatal_with_name (archive);
  912.  
  913.   if (arcfd >= 0)
  914.     {
  915.       if (!silent_create)
  916.     printf ("Creating archive file `%s'\n", archive);
  917.     }
  918.   else
  919.     arcfd = open (archive, O_RDWR, 0);
  920.  
  921.   /* If the file suddenly doesn't exist, punt.  Some user must have
  922.      manually deleted the file.  */
  923.   if (arcfd < 0)
  924.     pfatal_with_name (archive);
  925.  
  926.   lock_a_file (arcfd, O_RDWR);
  927.  
  928.   /* Whew.  Now that we've got the file and it's locked, check whether
  929.      it's really an archive or just an empty shell, created either by
  930.      us or by a competing ar.  */
  931.  
  932.   fstat (arcfd, &statbuf);
  933.   if (statbuf.st_size == 0)
  934.     mywrite (arcfd, ARMAG, SARMAG, archive);
  935.   else
  936.     verify_is_archive (arcfd);
  937.  
  938.   arcstream = fdopen (arcfd, "r+");
  939.   if (arcstream == 0)
  940.     fatal ("can't create stream for archive");
  941. }
  942.  
  943. #ifndef LOCKS
  944.  
  945. void
  946. lock_a_file (fd, how)
  947.      int fd, how;
  948. {
  949. }
  950.  
  951. void
  952. unlock_a_file (fd)
  953.      int fd;
  954. {
  955. }
  956.  
  957. #else /* LOCKS */
  958.  
  959. /* Lock the old file so that it won't be written while there are
  960.    readers or another writer.
  961.    Non-sprite systems use the fcntl locking facility found on Sun
  962.    systems, which is also in POSIX.  (Perhaps it comes from sysV.)  */
  963.  
  964. #ifndef LOCK_FLOCK
  965.  
  966. void
  967. lock_a_file (fd, how)
  968.      int fd;
  969.      int how;                /* read/write flag */
  970. {
  971.   struct flock lock;
  972.  
  973.   lock.l_type = (how == O_RDONLY ? F_RDLCK : F_WRLCK);
  974.   lock.l_whence = 0;
  975.   lock.l_start = 0;
  976.   lock.l_len = 0;
  977.  
  978.   while (1)
  979.     {
  980.       int value = fcntl (fd, F_SETLKW, &lock);
  981.       if (value >= 0)
  982.     break;
  983.       else if (errno == EINTR)
  984.     continue;
  985.       else
  986.     pfatal_with_name ("locking archive");
  987.     }
  988. }
  989.  
  990. void
  991. unlock_a_file (fd)
  992.      int fd;
  993.   {
  994.     struct flock lock;
  995.  
  996.     /* Unlock the old archive.  */
  997.  
  998.     lock.l_type = F_UNLCK;
  999.     lock.l_whence = 0;
  1000.     lock.l_start = 0;
  1001.     lock.l_len = 0;
  1002.  
  1003.     fcntl (fd, F_SETLK, &lock);
  1004.   }
  1005.  
  1006. #else /* LOCK_FLOCK */
  1007.  
  1008. void
  1009. lock_a_file (fd, how)
  1010.      int fd;
  1011.      int how;                /* read/write flag */
  1012. {
  1013.   int lock_type = (how == O_RDONLY ? LOCK_SH : LOCK_EX);
  1014.  
  1015.   open_flags = how;
  1016.   if (flock (fd, lock_type) < 0)
  1017.     pfatal_with_name (archive);
  1018. }
  1019.  
  1020. /* Putting lock_flags in the flock() call is a workaround for a bug in 
  1021.    Sprite's flock() emulation.  -mdk 19-Oct-90 */
  1022.  
  1023. void
  1024. unlock_a_file (fd)
  1025.      int fd;
  1026. {
  1027.   int lock_type = (open_flags == O_RDONLY ? LOCK_SH : LOCK_EX);
  1028.  
  1029.   if (flock (fd, LOCK_UN | lock_type) < 0)
  1030.     pfatal_with_name (archive);
  1031. }
  1032.  
  1033. #endif /* LOCK_FLOCK */
  1034. #endif /* LOCKS */
  1035.  
  1036. /* Unlock archive and close the file descriptor.  */
  1037.  
  1038. void
  1039. close_archive ()
  1040. {
  1041. #ifndef USG
  1042.   fsync (arcfd);
  1043. #endif
  1044.   unlock_a_file (arcfd);
  1045.   if (close (arcfd) < 0)
  1046.     {
  1047.       perror_with_name (archive);
  1048.       exit (1);
  1049.     }
  1050. }
  1051.  
  1052. /* Ensure that the given file is an archive.  Side effect: repositions
  1053.    the archive.  After calling this routine, you should do a seek.  */
  1054.  
  1055. void
  1056. verify_is_archive (fd)
  1057.      int fd;
  1058. {
  1059.   char buf[SARMAG];
  1060.   int nread;
  1061.  
  1062.   lseek (fd, 0, L_SET);
  1063.   nread = read (fd, buf, sizeof (buf));
  1064.   if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG) != 0)
  1065.     fatal ("file %s not a valid archive", archive);
  1066. }
  1067.  
  1068. /* Write a new archive file from a given map.  */
  1069. /* When a map is used as the pattern for a new archive,
  1070.    each element represents one member to put in it, and
  1071.    the order of elements controls the order of writing.
  1072.   
  1073.    Ordinarily, the element describes a member of the old
  1074.    archive, to be copied into the new one.
  1075.   
  1076.    If, however, the `offset' field of the element's info is 0,
  1077.    then the element describes a file to be copied into the
  1078.    new archive.
  1079.  
  1080.    The archive is updated by writing a new file and then copying the
  1081.    new file onto the old one.  We don't use rename, because if some
  1082.    other "ar" has the archive open and is waiting to obtain the lock,
  1083.    it would end up with the old file, not the new one.  There can
  1084.    never be two ar's writing the new file simultaneously, because of
  1085.    the lock on the archive.
  1086. */
  1087.  
  1088. char *make_tempname ();
  1089. void copy_out_member ();
  1090. void copy_file ();
  1091.  
  1092. void
  1093. write_archive (map, appendflag)
  1094.      struct mapelt *map;
  1095.      int appendflag;
  1096. {
  1097.   char *tempname = make_tempname (archive);
  1098.   int indesc = arcfd;
  1099.   int outdesc;
  1100.   char *outname;
  1101.   struct mapelt *tail;
  1102.  
  1103.   /* Sanity check */
  1104.  
  1105.   if (open_flags == O_RDONLY)
  1106.     fatal ("want to update archive after declaring read-only");
  1107.  
  1108.   /* Now open the output.  */
  1109.  
  1110.   if (!appendflag)
  1111.     {
  1112.       /* Write the revised archive to TEMPNAME, then copy it back. */
  1113.  
  1114.       outdesc = open (tempname, O_RDWR | O_CREAT, 0666);
  1115.       if (outdesc < 0)
  1116.     pfatal_with_name (tempname);
  1117.       outname = tempname;
  1118.       mywrite (outdesc, ARMAG, SARMAG, outname);
  1119.     }
  1120.   else
  1121.     {
  1122.       /* Fast-append to existing archive.  */
  1123.  
  1124.       outdesc = open (archive, O_WRONLY | O_APPEND, 0);
  1125.       if (outdesc < 0)
  1126.     pfatal_with_name (archive);
  1127.       outname = archive;
  1128.     }
  1129.  
  1130.   /* If archive has or should have a __.SYMDEF member,
  1131.      compute the contents for it.  */
  1132.  
  1133.   if (symdef_flag || symdef_exists)
  1134.     {
  1135.       if (symdef_exists)
  1136.     read_old_symdefs (map, indesc);
  1137.       else
  1138.     {
  1139.       struct mapelt *this = (struct mapelt *)
  1140.         xmalloc (sizeof (struct mapelt));
  1141.       init_name (&this->info.name, "__.SYMDEF");
  1142.       this->info.offset = SARMAG;
  1143.       this->info.data_offset = SARMAG + sizeof (struct ar_hdr);
  1144.       this->info.new_offset = 0;
  1145.       this->info.date = 0;
  1146.       this->info.size = 0;
  1147.       this->info.uid = 0;
  1148.       this->info.gid = 0;
  1149.       this->info.mode = 0666;
  1150.       this->info.symdefs = 0;
  1151.       this->info.nsymdefs = 0;
  1152.       this->info.string_size = 0;
  1153.       this->next = map;
  1154.       map = this;
  1155.       original_num_symdefs = 0;
  1156.       old_strings_size = 0;
  1157.     }
  1158.  
  1159.       update_symdefs (map, indesc);
  1160.     }
  1161.  
  1162.   /* Copy the members into the output, either from the old archive
  1163.      or from specified files.  */
  1164.  
  1165.   for (tail = map; tail != 0; tail = tail->next)
  1166.     {
  1167.       if ((symdef_flag || symdef_exists) && !marked_for_deletion(tail)
  1168.       && name_match (&tail->info.name, &symdef_name)
  1169. #if 0
  1170.       && tail->info.date==0
  1171. #endif
  1172.       )
  1173.     write_symdef_member (tail, map, outdesc, outname);
  1174.       else
  1175.     copy_out_member (tail, indesc, outdesc, outname);
  1176.     }
  1177.  
  1178.   if (symdef_mapelt != 0)
  1179.     {
  1180.       /* Check for members whose data offsets weren't
  1181.      known when the symdef member was first written.  */
  1182.       int doneany = 0;
  1183.       for (tail = map; tail != 0; tail = tail->next)
  1184.     if (tail->info.offset == 0)
  1185.       {
  1186.         /* Fix up the symdefs.  */
  1187.         register unsigned int i;
  1188.         for (i = 0; i < tail->info.nsymdefs; ++i)
  1189.           tail->info.symdefs[i].offset = tail->info.new_offset;
  1190.         doneany = 1;
  1191.       }
  1192.       if (doneany)
  1193.     {
  1194.       /* Some files had bad symdefs; rewrite the symdef member.  */
  1195.       lseek (outdesc, symdef_mapelt->info.offset, 0);
  1196.       write_symdef_member (symdef_mapelt, map, outdesc, outname);
  1197.     }
  1198.     }
  1199.  
  1200.   /* Mark the __.SYMDEF member as up to date.  */
  1201.  
  1202.   if (symdef_mapelt != 0)
  1203.     touch_symdef_member (outdesc, outname);
  1204.  
  1205.   if (!appendflag)
  1206.     copy_file (outdesc, tempname, arcfd, archive);
  1207.   close (outdesc);
  1208.   if (!appendflag)
  1209.     unlink (tempname);
  1210.  
  1211.   close_archive ();
  1212. }
  1213.  
  1214. /* Copy all of fromfd to tofd.  The file names are passed in for error
  1215.    reporting.  */
  1216.  
  1217. void
  1218. copy_file (from_fd, from_name, to_fd, to_name)
  1219.      int from_fd, to_fd;
  1220.      char *from_name, *to_name;
  1221. {
  1222.   char buf[8192];
  1223.   int nchars;
  1224.  
  1225.   lseek (from_fd, 0, L_SET);
  1226.   lseek (to_fd, 0, L_SET);
  1227.   if (ftruncate (to_fd, 0) < 0)
  1228.     pfatal_with_name (to_name);
  1229.  
  1230.   while ((nchars = read (from_fd, buf, sizeof (buf))) > 0)
  1231.     {
  1232.       if (write (to_fd, buf, nchars) != nchars) 
  1233.     pfatal_with_name (to_name);
  1234.     }
  1235.   if (nchars < 0)
  1236.     pfatal_with_name (from_name);
  1237. }
  1238.  
  1239. /* Fill in an ar header for an element of the archive.  */
  1240.  
  1241. void
  1242. header_from_map (header, mapelt)
  1243.      struct ar_hdr *header;
  1244.      struct mapelt *mapelt;
  1245. {
  1246.   /* Zero the header, then store in the data as text.  */
  1247.   bzero ((char *) header, sizeof (*header));
  1248.  
  1249.   assert (mapelt->info.name.stored != NULL);
  1250.   assert (strlen (mapelt->info.name.stored) < sizeof (header->ar_name));
  1251.   strcpy (header->ar_name, mapelt->info.name.stored);
  1252.  
  1253.   sprintf (header->ar_date, "%ld", mapelt->info.date);
  1254.   sprintf (header->ar_size, "%d", mapelt->info.size);
  1255.   sprintf (header->ar_uid, "%d", mapelt->info.uid);
  1256.   sprintf (header->ar_gid, "%d", mapelt->info.gid);
  1257.   sprintf (header->ar_mode, "%o", mapelt->info.mode);
  1258.   strncpy (header->ar_fmag, ARFMAG, sizeof (header->ar_fmag));
  1259.  
  1260.   /* Change all remaining nulls in the header into spaces.  */
  1261.   {
  1262.     char *end = (char *) &header[1];
  1263.     register char *p;
  1264.     for (p = (char *) header; p < end; ++p)
  1265.       if (*p == '\0')
  1266.     *p = ' ';
  1267.   }
  1268. }
  1269.  
  1270. /* writes to file open on OUTDESC with name OUTNAME.  */
  1271. void
  1272. copy_out_member (mapelt, archive_indesc, outdesc, outname)
  1273.      struct mapelt *mapelt;
  1274.      int archive_indesc;
  1275.      int outdesc;
  1276.      char *outname;
  1277. {
  1278.   struct ar_hdr header;
  1279.   int indesc;
  1280.  
  1281.   if (marked_for_deletion (mapelt))
  1282.     return;
  1283.  
  1284.   header_from_map (&header, mapelt);
  1285.  
  1286.   /* Either copy the member from the (old) archive, or copy it from 
  1287.      the user-named filed.  */
  1288.   if (mapelt->info.offset != 0)
  1289.     {
  1290.       indesc = archive_indesc;
  1291.       lseek (indesc, mapelt->info.data_offset, 0);
  1292.     }
  1293.   else
  1294.     {
  1295.       assert (mapelt->info.name.given != NULL);
  1296.       indesc = open (mapelt->info.name.given, O_RDONLY, 0);
  1297.       if (indesc < 0)
  1298.     {
  1299.       perror_with_name (mapelt->info.name.given);
  1300.       return;
  1301.     }
  1302.     }
  1303.  
  1304.   mywrite (outdesc, &header, sizeof (header), outname);
  1305.  
  1306.   if (mapelt->info.data_offset == 0)
  1307.     mapelt->info.data_offset = lseek (outdesc, 0L, 1);
  1308.  
  1309.   {
  1310.     char buf[BUFSIZE];
  1311.     int tocopy = mapelt->info.size;
  1312.     while (tocopy > 0)
  1313.       {
  1314.     int thistime = tocopy;
  1315.     if (thistime > BUFSIZE) thistime = BUFSIZE;
  1316.         read (indesc, buf, thistime);
  1317.     mywrite (outdesc, buf, thistime, outname);
  1318.     tocopy -= thistime;
  1319.       }
  1320.   }
  1321.  
  1322.   if (indesc != archive_indesc)
  1323.     close (indesc);
  1324.  
  1325.   if (mapelt->info.size & 1)
  1326.     mywrite (outdesc, "\n", 1, outname);
  1327. }
  1328.  
  1329. /* Update the time of the __.SYMDEF member; done when we updated
  1330.    that member, just before we close the new archive file.
  1331.    It is open on OUTDESC and its name is OUTNAME.  */
  1332.  
  1333. void
  1334. touch_symdef_member (outdesc, outname)
  1335.      int outdesc;
  1336.      char *outname;
  1337. {
  1338.   struct stat statbuf;
  1339.   int i;
  1340.  
  1341.   /* See what mtime the archive file has as a result of our writing it.  */
  1342.   fstat (outdesc, &statbuf);
  1343.  
  1344.   /* Advance member's time to that time.  */
  1345.   bzero (symdef_header.ar_date, sizeof symdef_header.ar_date);
  1346.   sprintf (symdef_header.ar_date, "%ld", statbuf.st_mtime);
  1347.   for (i = 0; i < sizeof symdef_header.ar_date; i++)
  1348.     if (symdef_header.ar_date[i] == 0)
  1349.       symdef_header.ar_date[i] = ' ';
  1350.  
  1351.   /* Write back this member's header with the new time.  */
  1352.   if (lseek (outdesc, symdef_mapelt->info.new_offset, 0) >= 0)
  1353.     mywrite (outdesc, &symdef_header, sizeof symdef_header, outname);
  1354. }
  1355.  
  1356. char *
  1357. make_tempname (name)
  1358.      char *name;
  1359. {
  1360.   return concat (name, "", "_supersede");
  1361. }
  1362.  
  1363. void
  1364. delete_members ()
  1365. {
  1366.   struct mapelt *map;
  1367.   struct mapelt mapstart;
  1368.   struct member_name *name;
  1369.  
  1370.   open_archive (O_RDWR);
  1371.  
  1372.   map = make_map (0);
  1373.   init_elt (&mapstart);
  1374.   mapstart.next = map;
  1375.   map = &mapstart;
  1376.  
  1377.   if (file_args)
  1378.     for (name = file_args; !Empty_Name(name); name++)
  1379.       {
  1380.     /* If user says to delete the __.SYMDEF member,
  1381.        don't make a new one to replace it.  */
  1382.     if (name_match (name, &symdef_name))
  1383.       symdef_exists = 0;
  1384.     delete_from_map (name, map);
  1385.       }
  1386.  
  1387.   write_archive (map->next, 0);
  1388. }
  1389.  
  1390. void
  1391. delete_from_map (name, map)
  1392.      struct member_name *name;
  1393.      struct mapelt *map;
  1394. {
  1395.   struct mapelt *this = find_mapelt (map, name);
  1396.  
  1397.   if (!this) return;
  1398.   mark_as_deleted (this);
  1399.   if (verbose)
  1400.     printf ("d - %s\n", name->stored);
  1401. }
  1402.  
  1403. void
  1404. move_members ()
  1405. {
  1406.   struct mapelt *map;
  1407.   struct member_name *name;
  1408.   struct mapelt *after_mapelt;
  1409.   struct mapelt mapstart;
  1410.   struct mapelt *change_map;
  1411.  
  1412.   open_archive (O_RDWR);
  1413.  
  1414.   map = make_map (0);
  1415.   init_elt (&mapstart);
  1416.   mapstart.next = map;
  1417.   change_map = &mapstart;
  1418.  
  1419.   switch (postype)
  1420.     {
  1421.     case POS_DEFAULT:
  1422.       after_mapelt = last_mapelt (change_map);
  1423.       break;
  1424.  
  1425.     case POS_AFTER:
  1426.       after_mapelt = find_mapelt (map, posname);
  1427.       break;
  1428.  
  1429.     case POS_BEFORE:
  1430.       after_mapelt = prev_mapelt (change_map, find_mapelt (map,
  1431.                                posname));
  1432.       break;
  1433.  
  1434.     default:
  1435.       after_mapelt = 0;            /* lint */
  1436.       fatal ("bogus position type");    /* "can't happen" */
  1437.     }
  1438.  
  1439.   /* Failure to find specified "before" or "after" member
  1440.      is a fatal error; message has already been printed.  */
  1441.  
  1442.   if (!after_mapelt) exit (1);
  1443.  
  1444.   if (file_args)
  1445.     for (name = file_args; !Empty_Name(name); name++)
  1446.       {
  1447.     if (move_in_map (name, change_map, after_mapelt))
  1448.       after_mapelt = after_mapelt->next;
  1449.       }
  1450.  
  1451.   write_archive (change_map->next, 0);
  1452. }
  1453.  
  1454. int
  1455. move_in_map (name, map, after)
  1456.      struct member_name *name;
  1457.      struct mapelt *map, *after;
  1458. {
  1459.   struct mapelt *this = find_mapelt (map, name);
  1460.   struct mapelt *prev;
  1461.  
  1462.   if (!this)
  1463.     return 0;
  1464.   prev = prev_mapelt (map, this);
  1465.   if (this == after || prev == after)
  1466.     return 1;                /* no-op */
  1467.   prev->next = this->next;
  1468.   this->next = after->next;
  1469.   after->next = this;
  1470.   return 1;
  1471. }
  1472.  
  1473. /* Insert files into the archive.  */
  1474.  
  1475. void
  1476. replace_members ()
  1477. {
  1478.   struct mapelt *map;
  1479.   struct mapelt mapstart;
  1480.   struct mapelt *after_mapelt;
  1481.   struct mapelt *change_map;
  1482.   struct member_name *name;
  1483.   int changed;
  1484.  
  1485.   open_archive (O_RDWR);
  1486.  
  1487.   map = make_map (1);
  1488.   init_elt (&mapstart);
  1489.   mapstart.next = map;
  1490.   change_map = &mapstart;
  1491.  
  1492.   switch (postype)
  1493.     {
  1494.     case POS_DEFAULT:
  1495.       after_mapelt = last_mapelt (change_map);
  1496.       break;
  1497.  
  1498.     case POS_AFTER:
  1499.       after_mapelt = find_mapelt (map, posname);
  1500.       break;
  1501.  
  1502.     case POS_BEFORE:
  1503.       after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
  1504.       break;
  1505.  
  1506.     default:
  1507.       after_mapelt = 0;            /* lint */
  1508.       fatal ("bogus position type");    /* "can't happen" */
  1509.     }
  1510.  
  1511.   /* Failure to find specified "before" or "after" member
  1512.      is a fatal error; the message has already been printed.  */
  1513.   if (after_mapelt == 0)
  1514.     exit (1);
  1515.  
  1516.   changed = 0;
  1517.   if (file_args)
  1518.     for (name = file_args; !Empty_Name(name); ++name)
  1519.       if (insert_in_map (name, change_map, after_mapelt))
  1520.     {
  1521.       after_mapelt = after_mapelt->next;
  1522.       changed = 1;
  1523.     }
  1524.  
  1525.   if (!changed && (!symdef_flag || symdef_exists))
  1526.     /* Nothing changed.  */
  1527.     close_archive ();
  1528.   else
  1529.     write_archive (change_map->next, 0);
  1530. }
  1531.  
  1532. /* Handle the "quick insert" operation.  */
  1533.  
  1534. void
  1535. quick_append ()
  1536. {
  1537.   struct mapelt *map;
  1538.   struct mapelt *after;
  1539.   struct mapelt mapstart;
  1540.   struct member_name *name;
  1541.  
  1542.   init_elt (&mapstart);
  1543.   mapstart.next = 0;
  1544.   map = &mapstart;
  1545.   after = map;
  1546.  
  1547.   open_archive (O_RDWR);
  1548.  
  1549.   /* Insert the specified files into the "map",
  1550.      but is a map of the inserted files only,
  1551.      and starts out empty.  */
  1552.   if (file_args)
  1553.     for (name = file_args; !Empty_Name(name); name++)
  1554.       {
  1555.     if (insert_in_map (name, map, after))
  1556.       after = after->next;
  1557.       }
  1558.  
  1559.   /* Append these files to the end of the existing archive file.  */
  1560.  
  1561.   write_archive (map->next, 1);
  1562. }
  1563.  
  1564. /* Insert an entry for REQUESTED_NAME into the map MAP after the map
  1565.    entry AFTER. 
  1566.    Deletes any old entry for REQUESTED_NAME.
  1567.    MAP is assumed to start with a dummy entry, which facilitates
  1568.    insertion at the beginning of the list.
  1569.    Return 1 if successful, 0 if did nothing because file
  1570.    REQUESTED_NAME doesn't exist or (optionally) is older.  */
  1571.  
  1572. int
  1573. insert_in_map (requested_name, map, after)
  1574.      struct member_name *requested_name;
  1575.      struct mapelt *map, *after;
  1576. {
  1577.   struct mapelt *old = find_mapelt_noerror (map, requested_name);
  1578.   struct mapelt *this;
  1579.   struct stat status;
  1580.  
  1581.   assert (requested_name->given != NULL);
  1582.   if (stat (requested_name->given, &status))
  1583.     {
  1584.       perror_with_name (requested_name->given);
  1585.       return 0;
  1586.     }
  1587.   if (old && newer_only && status.st_mtime <= old->info.date)
  1588.     return 0;
  1589.  
  1590.   this = (struct mapelt *) xmalloc (sizeof (struct mapelt));
  1591.   if (old)
  1592.     mark_as_deleted (old);
  1593.  
  1594.   this->info.name = *requested_name;
  1595.   this->info.offset = 0;
  1596.   this->info.data_offset = 0;
  1597.   this->info.date = status.st_mtime;
  1598.   this->info.size = status.st_size;
  1599.   this->info.uid = status.st_uid;
  1600.   this->info.gid = status.st_gid;
  1601.   this->info.mode = status.st_mode;
  1602.   this->next = after->next;
  1603.   after->next = this;
  1604.  
  1605.   if (verbose)
  1606.     printf ("%c - %s\n", old == 0 ? 'a' : 'r', this->info.name.stored);
  1607.  
  1608.   return 1;
  1609. }
  1610.  
  1611. /* Apply a function to each of the specified members.
  1612. */
  1613.  
  1614. void
  1615. extract_members (function)
  1616.      void (*function) ();
  1617. {
  1618.   struct mapelt *map;
  1619.   struct member_name *name;
  1620.  
  1621.   if (!file_args)
  1622.     {
  1623.       /* Handle case where we want to operate on every member.
  1624.      No need to make a map and search it for this.  */
  1625.       scan (function, 0);
  1626.       return;
  1627.     }
  1628.  
  1629.   if (arcstream == 0)
  1630.     open_archive (O_RDONLY);
  1631.   if (arcstream == 0)
  1632.     fatal ("failure opening archive %s for the second time", archive);
  1633.   verify_is_archive (arcfd);
  1634.   map = make_map (0);
  1635.  
  1636.   for (name = file_args; !Empty_Name(name); name++)
  1637.     {
  1638.       struct mapelt *this = find_mapelt (map, name);
  1639.       if (!this) continue;
  1640.       function (this->info, arcstream);
  1641.     }
  1642. }
  1643.  
  1644. /* Write the __.SYMDEF member from data in core.  OUTDESC and OUTNAME
  1645.    are descriptor and name of file to write to.  */
  1646.  
  1647. void
  1648. write_symdef_member (mapelt, map, outdesc, outname)
  1649.      struct mapelt *mapelt;
  1650.      struct mapelt *map;
  1651.      int outdesc;
  1652.      char *outname;
  1653. {
  1654.   struct ar_hdr header;
  1655.   struct mapelt *mapptr;
  1656.   unsigned long int symdefs_size;
  1657.   int symdef_sanity_count;
  1658.  
  1659.   if (marked_for_deletion (mapelt))
  1660.     return;
  1661.  
  1662.   header_from_map (&header, mapelt);
  1663.  
  1664.   bcopy (&header, &symdef_header, sizeof header);
  1665.  
  1666.   mywrite (outdesc, &header, sizeof (header), outname);
  1667.  
  1668.   /* Write the number of bytes taken by the symdef table.  */
  1669.   symdefs_size = nsymdefs * sizeof (struct symdef);
  1670.   mywrite (outdesc, &symdefs_size, sizeof symdefs_size, outname);
  1671.  
  1672.   /* Write symdefs surviving from old archive.  */
  1673.   mywrite (outdesc, old_symdefs, num_old_symdefs * sizeof (struct symdef),
  1674.        outname);
  1675.   symdef_sanity_count = num_old_symdefs;
  1676.  
  1677. #if DEBUG
  1678.   verify_symdefs (map, old_symdefs, num_old_symdefs, new_strings);
  1679. #endif
  1680.  
  1681.   /* Write symdefs for new members.  */
  1682.   for (mapptr = map; mapptr != 0; mapptr = mapptr->next)
  1683.     if (mapptr->info.nsymdefs != 0)
  1684.       {
  1685.     write (outdesc, mapptr->info.symdefs,
  1686.            mapptr->info.nsymdefs * sizeof (struct symdef));
  1687. #if DEBUG
  1688.     verify_symdefs (map, mapptr->info.symdefs, mapptr->info.nsymdefs,
  1689.             new_strings);
  1690. #endif
  1691.     symdef_sanity_count += mapptr->info.nsymdefs;
  1692.       }
  1693.  
  1694.   if (symdef_sanity_count != nsymdefs)
  1695.     fatal ("bug: wrote wrong number of symdefs");
  1696.  
  1697.   /* Write the string table size.  */
  1698.   mywrite (outdesc, &new_strings_size, sizeof new_strings_size, outname);
  1699.  
  1700.   /* Write the string table.  */
  1701.   mywrite (outdesc, new_strings, new_strings_size, outname);
  1702.  
  1703.   if (mapelt->info.size & 1)
  1704.     mywrite (outdesc, "", 1, outname);
  1705. }
  1706.  
  1707. #if DEBUG
  1708.  
  1709. /* Verify that the given symdefs point to the right place.  Treat the
  1710.    symbol as the name of a .o file and look it up.  If we find it,
  1711.    make sure we are pointing to it and not to some other .o file.  */
  1712.  
  1713. void
  1714. verify_symdefs (map, symdefs, numsymdefs, string_table)
  1715.      struct mapelt *map;
  1716.      struct symdef *symdefs;
  1717.      unsigned int numsymdefs;
  1718.      char *string_table;
  1719. {
  1720.   struct symdef *sym;
  1721.   struct member_name file_name;
  1722.   struct mapelt *member;
  1723.   char *tmp_name;
  1724.  
  1725.   for (sym = symdefs; sym < symdefs+numsymdefs; ++sym)
  1726.     {
  1727.       tmp_name = concat (string_table + sym->s.stringoffset, ".o", "");
  1728.       init_name (&file_name, (tmp_name[0] == '_' ? tmp_name+1 : tmp_name));
  1729.       member = find_mapelt_noerror (map, &file_name);
  1730.       if (member)
  1731.     {
  1732.       if (member->info.new_offset)
  1733.         {
  1734.           if (member->info.new_offset != sym->offset)
  1735.         {
  1736.           printf ("Symbol %s points to 0x%x, which doesn't match \
  1737. 0x%x (old 0x%x)\n",
  1738.               string_table + sym->s.stringoffset,
  1739.               sym->offset,
  1740.               member->info.new_offset,
  1741.               member->info.offset);
  1742.           abort ();
  1743.         }
  1744.         }
  1745.       /* else no new offset, so check the old one */
  1746.       else if (member->info.offset != sym->offset)
  1747.         {
  1748.           printf ("Symbol %s points to 0x%x, which doesn't match 0x%x\n",
  1749.               string_table + sym->s.stringoffset,
  1750.               sym->offset,
  1751.               member->info.offset);
  1752.           abort();
  1753.         }
  1754.     }
  1755.       free_name_strings (&file_name);
  1756.       free (tmp_name);
  1757.     }
  1758. }
  1759.  
  1760. #endif /* DEBUG */
  1761.  
  1762. void
  1763. read_old_symdefs (map, archive_indesc)
  1764.      struct mapelt *map;
  1765.      int archive_indesc;
  1766. {
  1767.   struct mapelt *mapelt;
  1768.   char *data;
  1769.   int symdefs_size;
  1770.  
  1771.   mapelt = find_mapelt_noerror (map, &symdef_name);
  1772.   if (!mapelt)
  1773.     abort ();            /* Only call here if an old one exists */
  1774.  
  1775.   data  = (char *) xmalloc (mapelt->info.size);
  1776.   lseek (archive_indesc, mapelt->info.data_offset, 0);
  1777.   if (read (archive_indesc, data, mapelt->info.size) !=
  1778.       mapelt->info.size)
  1779.     pfatal_with_name (archive);
  1780.  
  1781.   symdefs_size = *(unsigned long int *) data;
  1782.   original_num_symdefs = symdefs_size / sizeof (struct symdef);
  1783.   old_symdefs = (struct symdef *) (data + sizeof (symdefs_size));
  1784.   old_strings_size
  1785.     = *(unsigned long int *) (old_symdefs + original_num_symdefs);
  1786.   old_strings = ((char *) (old_symdefs + original_num_symdefs)
  1787.          + sizeof (old_strings_size));
  1788. #if DEBUG
  1789.   verify_symdefs (map, old_symdefs, original_num_symdefs, old_strings);
  1790. #endif
  1791. }
  1792.  
  1793. /* Read various information from the header of an object file.
  1794.    Return 0 for failure or 1 for success.  */
  1795.  
  1796. int
  1797. read_header_info (mapelt, desc, offset, syms_offset, syms_size, strs_offset,
  1798.           strs_size)
  1799.      struct mapelt *mapelt;
  1800.      int desc;
  1801.      long int offset;
  1802.      long int *syms_offset;
  1803.      unsigned int *syms_size;
  1804.      long int *strs_offset;
  1805.      unsigned int *strs_size;
  1806. {
  1807. #ifdef A_OUT
  1808.   {
  1809.     struct exec hdr;
  1810.  
  1811.     lseek (desc, offset, 0);
  1812. #ifdef HEADER_SEEK_FD
  1813.     HEADER_SEEK_FD (desc);
  1814. #endif
  1815.  
  1816.     if (read (desc, (char *) &hdr, sizeof hdr) == sizeof hdr && !N_BADMAG(hdr))
  1817.       {
  1818.     *syms_offset = N_SYMOFF (hdr);
  1819.     *syms_size = hdr.a_syms;
  1820.     *strs_offset = N_STROFF (hdr);
  1821.     lseek (desc, N_STROFF (hdr) + offset, 0);
  1822.     if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
  1823.       {
  1824.         error_with_file ("failure reading string table size in ", mapelt);
  1825.         return 0;
  1826.       }
  1827.     return 1;
  1828.       }
  1829.   }
  1830. #endif
  1831.  
  1832. #ifdef MACH_O
  1833.   {
  1834.     struct mach_header mach_header;
  1835.     struct load_command *load_command;
  1836.     struct symtab_command *symtab_command;
  1837.     char *hdrbuf;
  1838.     int cmd, symtab_seen;
  1839.  
  1840.     lseek (desc, offset, 0);
  1841.     if (read (desc, (char *) &mach_header, sizeof mach_header) == sizeof mach_header
  1842.     && mach_header.magic == MH_MAGIC)
  1843.       {
  1844.     hdrbuf = xmalloc (mach_header.sizeofcmds);
  1845.     if (read (desc, hdrbuf, mach_header.sizeofcmds) != mach_header.sizeofcmds)
  1846.       {
  1847.         error_with_file ("failure reading load commands of ", mapelt);
  1848.         return 0;
  1849.       }
  1850.     load_command = (struct load_command *) hdrbuf;
  1851.     symtab_seen = 0;
  1852.     for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
  1853.       {
  1854.         if (load_command->cmd == LC_SYMTAB)
  1855.           {
  1856.         symtab_seen = 1;
  1857.         symtab_command = (struct symtab_command *) load_command;
  1858.         *syms_offset = symtab_command->symoff;
  1859.         *syms_size = symtab_command->nsyms * sizeof (struct nlist);
  1860.         *strs_offset = symtab_command->stroff;
  1861.         *strs_size = symtab_command->strsize;
  1862.           }
  1863.         load_command = (struct load_command *) ((char *) load_command + load_command->cmdsize);
  1864.       }
  1865.     free (hdrbuf);
  1866.     if (!symtab_seen)
  1867.       *syms_offset = *syms_size = *strs_offset = *strs_size = 0;
  1868.     return 1;
  1869.       }
  1870.   }
  1871. #endif
  1872.  
  1873.   error_with_file ("bad format (not an object file) in ", mapelt);
  1874.   return 0;
  1875. }
  1876.  
  1877. /* Create the info.symdefs for a new member
  1878.    by reading the file it is coming from.  */
  1879.  
  1880. void
  1881. make_new_symdefs (mapelt, archive_indesc)
  1882.      struct mapelt *mapelt;
  1883.      int archive_indesc;
  1884. {
  1885.   int indesc;
  1886.   long int syms_offset, strs_offset;
  1887.   unsigned int syms_size, strs_size;
  1888.   struct nlist *symbols;
  1889.   int symcount;
  1890.   char *strings;
  1891.   register unsigned int i;
  1892.   unsigned long int offset;
  1893.  
  1894.   if (marked_for_deletion (mapelt))
  1895.     fatal ("trying to make symdefs for deleted member");
  1896.  
  1897.   /* Either use an existing member from the archive, or use the 
  1898.      user-specified file.  */
  1899.  
  1900.   if (mapelt->info.offset != 0)
  1901.     {
  1902.       indesc = archive_indesc;
  1903.       lseek (indesc, mapelt->info.data_offset, 0);
  1904.       offset = mapelt->info.data_offset;
  1905.     }
  1906.   else
  1907.     {
  1908.       assert (mapelt->info.name.given != NULL);
  1909.       indesc = open (mapelt->info.name.given, O_RDONLY, 0);
  1910.       if (indesc < 0)
  1911.     {
  1912.       perror_with_name (mapelt->info.name.given);
  1913.       return;
  1914.     }
  1915.       offset = 0;
  1916.     }
  1917.  
  1918.   if (!read_header_info (mapelt, indesc, (long) offset, &syms_offset,
  1919.              &syms_size, &strs_offset, &strs_size))
  1920.     {
  1921.       if (mapelt->info.offset == 0)
  1922.     close (indesc);
  1923.       return;
  1924.     }
  1925.  
  1926.   /* Number of symbol entries in the file.  */
  1927.   symcount = syms_size / sizeof (struct nlist);
  1928.   /* Allocate temporary space for the symbol entries.  */
  1929.   symbols = (struct nlist *) alloca (syms_size);
  1930.   /* Read in the symbols.  */
  1931.   lseek (indesc, syms_offset + offset, 0);
  1932.   if (read (indesc, (char *) symbols, syms_size) != syms_size)
  1933.     {
  1934.       error_with_file ("premature end of file in symbols of ", mapelt);
  1935.       if (mapelt->info.offset == 0)
  1936.     (void) close (indesc);
  1937.       return;
  1938.     }
  1939.  
  1940.   /* The string table size includes the size word.  */
  1941.   if (strs_size < sizeof (strs_size))
  1942.     {
  1943.       error_with_file ("bad string table size in ", mapelt);
  1944.       if (mapelt->info.offset == 0)
  1945.     (void) close (indesc);
  1946.       return;
  1947.     }
  1948.   strs_size -= sizeof (strs_size);
  1949.  
  1950.   /* Allocate permanent space for the string table.  */
  1951.   strings = (char *) xmalloc (strs_size);
  1952.  
  1953.   /* Read in the strings.  */
  1954.   lseek (indesc, offset + strs_offset + sizeof strs_size, 0);
  1955.   if (read (indesc, strings, strs_size) != strs_size)
  1956.     {
  1957.       error_with_file ("premature end of file in strings of ", mapelt);
  1958.       if (mapelt->info.offset == 0)
  1959.     (void) close (indesc);
  1960.       return;
  1961.     }
  1962.  
  1963.   if (indesc != archive_indesc)
  1964.     (void) close (indesc);
  1965.  
  1966.   /* Discard the symbols we don't want to mention; compact the rest down.  */
  1967.   symcount = filter_symbols (symbols, (unsigned) symcount);
  1968.  
  1969.   mapelt->info.symdefs = (struct symdef *)
  1970.     xmalloc (symcount * sizeof (struct symdef));
  1971.   mapelt->info.nsymdefs = symcount;
  1972.   mapelt->info.string_size = 0;
  1973.  
  1974.   for (i = 0; i < symcount; ++i)
  1975.     {
  1976.       unsigned long int stroff = symbols[i].n_un.n_strx - sizeof (strs_size);
  1977.       char *symname = strings + stroff;
  1978.       if (stroff > strs_size)
  1979.     {
  1980.       char buf[100];
  1981.       sprintf (buf, "ridiculous string offset %lu in symbol %u of ",
  1982.            stroff + sizeof (strs_size), i);
  1983.       error_with_file (buf, mapelt);
  1984.       return;
  1985.     }
  1986.       mapelt->info.symdefs[i].s.name = symname;
  1987.       mapelt->info.string_size += strlen (symname) + 1;
  1988.     }
  1989. }
  1990.  
  1991. /* Choose which symbol entries to mention in __.SYMDEF;
  1992.    compact them downward to get rid of the rest.
  1993.    Return the number of symbols left.  */
  1994.  
  1995. int
  1996. filter_symbols (syms, symcount)
  1997.      struct nlist *syms;
  1998.      unsigned int symcount;
  1999. {
  2000.   struct nlist *from, *to;
  2001.   struct nlist *end = syms + symcount;
  2002.  
  2003.   for (to = from = syms; from < end; ++from)
  2004.     if ((from->n_type & N_EXT)
  2005.     && (from->n_type != N_EXT || from->n_value != 0))
  2006.       *to++ = *from;
  2007.  
  2008.   return to - syms;
  2009. }
  2010.  
  2011.  
  2012. /* Update the __.SYMDEF data before writing a new archive.  */
  2013.  
  2014. void
  2015. update_symdefs (map, archive_indesc)
  2016.      struct mapelt *map;
  2017.      int archive_indesc;
  2018. {
  2019.   struct mapelt *tail;
  2020.   int pos;
  2021.   register unsigned int i;
  2022.   unsigned int len;
  2023.   struct symdef *s;
  2024.   unsigned long int deleted_strings_size = 0;
  2025.   unsigned long *newoffsets = 0;
  2026.  
  2027.   nsymdefs = original_num_symdefs;
  2028.   num_old_symdefs = original_num_symdefs;
  2029.   new_strings_size = old_strings_size;
  2030.  
  2031.   if (nsymdefs != 0)
  2032.     {
  2033.       /* We already had a __.SYMDEF member, so just update it.  */
  2034.  
  2035.       /* Mark as cancelled any old symdefs for members being deleted.  */
  2036.  
  2037.       for (tail = map; tail != 0; tail = tail->next)
  2038.     {
  2039.       if (marked_for_deletion (tail))
  2040.         {
  2041.           assert (tail->info.offset != 0);
  2042.           /* Old member being deleted.  Delete its symdef entries too.  */
  2043.           for (i = 0; i < original_num_symdefs; i++)
  2044.         if (old_symdefs[i].offset == tail->info.offset)
  2045.           {
  2046.             old_symdefs[i].offset = 0;
  2047.             --nsymdefs;
  2048.             deleted_strings_size
  2049.               += strlen (old_strings
  2050.                  + old_symdefs[i].s.stringoffset) + 1;
  2051.           }
  2052.         }
  2053.     }
  2054.  
  2055.       /* Compactify old symdefs.  */
  2056.       {
  2057.     register unsigned int j = 0;
  2058.     for (i = 0; i < num_old_symdefs; ++i)
  2059.       {
  2060.         if (j != i)
  2061.           old_symdefs[j] = old_symdefs[i];
  2062.         if (old_symdefs[i].offset != 0)
  2063.           ++j;
  2064.       }
  2065.     num_old_symdefs -= i - j;
  2066.       }
  2067.  
  2068.       /* Create symdef data for any new members.  */
  2069.       for (tail = map; tail != 0; tail = tail->next)
  2070.     {
  2071.       if (tail->info.offset != 0
  2072.           || marked_for_deletion (tail)
  2073.           || name_match (&tail->info.name, &symdef_name))
  2074.         continue;
  2075.       make_new_symdefs (tail, archive_indesc);
  2076.       nsymdefs += tail->info.nsymdefs;
  2077.       new_strings_size += tail->info.string_size;
  2078.     }
  2079.     }
  2080.   else
  2081.     {
  2082.       /* Create symdef data for all existing members.  */
  2083.  
  2084.       for (tail = map; tail != 0; tail = tail->next)
  2085.     {
  2086.       if (marked_for_deletion (tail)
  2087.           || name_match (&tail->info.name, &symdef_name))
  2088.         continue;
  2089.       make_new_symdefs (tail, archive_indesc);
  2090.       nsymdefs += tail->info.nsymdefs;
  2091.       new_strings_size += tail->info.string_size;
  2092.     }
  2093.     }
  2094.  
  2095.   new_strings_size -= deleted_strings_size;
  2096.   old_strings_size -= deleted_strings_size;
  2097.  
  2098. #if DEBUG
  2099.   verify_symdefs (map, old_symdefs, num_old_symdefs, old_strings);
  2100. #endif
  2101.  
  2102.   /* Now we know the size of __.SYMDEF,
  2103.      so assign the positions of all the members.  */
  2104.  
  2105.   tail = find_mapelt_noerror (map, &symdef_name);
  2106.   tail->info.size = (sizeof (nsymdefs) + (nsymdefs * sizeof (struct symdef))
  2107.              + sizeof (new_strings_size) + new_strings_size);
  2108.   symdef_mapelt = tail;
  2109.  
  2110.   pos = SARMAG;
  2111.   for (tail = map; tail != 0; tail = tail->next)
  2112.     {
  2113.       if (marked_for_deletion (tail))
  2114.     continue;
  2115.       tail->info.new_offset = pos;
  2116.       pos += sizeof (struct ar_hdr) + tail->info.size;
  2117.       if (tail->info.size & 1)
  2118.     ++pos;
  2119.     }
  2120.  
  2121.   /* Now update the offsets in the symdef data to be the new offsets
  2122.      rather than the old ones.  We can't update the old symdefs in
  2123.      place, because the new offset for one member might match the old
  2124.      offset for another member.  So for the old symdefs we mark in a
  2125.      separate array what the new offsets are and then update the
  2126.      symdefs after going through all the members.  */
  2127.  
  2128.   newoffsets =
  2129.     (unsigned long *)xmalloc (num_old_symdefs * sizeof(unsigned long));
  2130.   bzero (newoffsets, num_old_symdefs * sizeof (unsigned long));
  2131.  
  2132.   for (tail = map; tail != 0; tail = tail->next)
  2133.     {
  2134.       if (marked_for_deletion (tail))
  2135.     continue;
  2136.       if (tail->info.symdefs == 0)
  2137.     {
  2138.       /* Member without new symdef data.
  2139.          Check the old symdef data; it may be included there. */
  2140.       assert (tail->info.offset != 0);
  2141.       for (i = 0; i < num_old_symdefs; i++)
  2142.         {
  2143.           if (old_symdefs[i].offset == tail->info.offset)
  2144.         newoffsets[i] = tail->info.new_offset;
  2145.         }
  2146.     }
  2147.       else
  2148.     for (i = 0; i < tail->info.nsymdefs; i++)
  2149.       tail->info.symdefs[i].offset = tail->info.new_offset;
  2150.     }
  2151.  
  2152.   /* Actually update any old symdefs that have new offsets. */
  2153.   for (i = 0; i < num_old_symdefs; i++)
  2154.     if (newoffsets[i] != 0)
  2155.       old_symdefs[i].offset = newoffsets[i];
  2156.  
  2157.   free (newoffsets);
  2158.   newoffsets = 0;
  2159.  
  2160. #if DEBUG
  2161.   verify_symdefs (map, old_symdefs, num_old_symdefs, old_strings);
  2162. #endif
  2163.  
  2164.   /* Generate new, combined string table and put each string's offset into the
  2165.      symdef that refers to it.  Note that old symdefs ref their strings by
  2166.      offsets into old_strings but new symdefs contain addresses of strings.  */
  2167.  
  2168.   new_strings = (char *) xmalloc (new_strings_size);
  2169.   pos = 0;
  2170.  
  2171.   /* Write the strings of the old symdefs and update the structures
  2172.      to contain indices into the string table instead of strings.  */
  2173.   for (i = 0; i < num_old_symdefs; i++)
  2174.     {
  2175.       strcpy (new_strings + pos, old_strings + old_symdefs[i].s.stringoffset);
  2176.       old_symdefs[i].s.stringoffset = pos;
  2177.       pos += strlen (new_strings + pos) + 1;
  2178.     }
  2179.   if (pos < old_strings_size)
  2180.     {
  2181.       unsigned int d = old_strings_size - pos;
  2182.       /* Correct the string table size.  */
  2183.       new_strings_size -= d;
  2184.       /* Correct the size of the `__.SYMDEF' member,
  2185.      since it contains the string table.  */
  2186.       symdef_mapelt->info.size -= d;
  2187.     }
  2188.   else if (pos > old_strings_size)
  2189.     fatal ("Old archive's string size was %u too small.",
  2190.        pos - old_strings_size);
  2191.  
  2192.   for (tail = map; tail != 0; tail = tail->next)
  2193.     if (tail->info.symdefs)
  2194.       {
  2195.     len = tail->info.nsymdefs;
  2196.     s = tail->info.symdefs;
  2197.  
  2198.     for (i = 0; i < len; i++)
  2199.       {
  2200.         strcpy (new_strings + pos, s[i].s.name);
  2201.         s[i].s.stringoffset = pos;
  2202.         pos += strlen (new_strings + pos) + 1;
  2203.       }
  2204.       }
  2205.   if (pos != new_strings_size)
  2206.     fatal ("internal error: inconsistency in new_strings_size", 0);
  2207. }
  2208.  
  2209. /* Print error message and usage message, and exit.  */
  2210.  
  2211. void
  2212. usage (s1, s2)
  2213.      char *s1, *s2;
  2214. {
  2215.   error (s1, s2);
  2216.   fprintf (stderr, "\
  2217. Usage: ar d|m|p|q|r|t|x [abiclouv] [position-name] archive file...\n");
  2218.   exit (1);
  2219. }
  2220.  
  2221. /* Print error message and exit.  */
  2222.  
  2223. void
  2224. fatal (s1, s2)
  2225.      char *s1, *s2;
  2226. {
  2227.   error (s1, s2);
  2228.   exit (1);
  2229. }
  2230.  
  2231. /* Print error message.  `s1' is printf control string, the rest are args.  */
  2232.  
  2233. void
  2234. error (s1, s2, s3, s4, s5)
  2235.      char *s1, *s2, *s3, *s4, *s5;
  2236. {
  2237.   fprintf (stderr, "ar: ");
  2238.   fprintf (stderr, s1, s2, s3, s4, s5);
  2239.   fprintf (stderr, "\n");
  2240. }
  2241.  
  2242. void
  2243. error_with_file (string, mapelt)
  2244.      char *string;
  2245.      struct mapelt *mapelt;
  2246. {
  2247.   fprintf (stderr, "ar: ");
  2248.   fprintf (stderr, string);
  2249.   if (mapelt->info.offset != 0)
  2250.     {
  2251.       assert (mapelt->info.name.stored != NULL);
  2252.       fprintf (stderr, "%s(%s)", archive, mapelt->info.name.stored);
  2253.     }
  2254.   else
  2255.     {
  2256.       assert (mapelt->info.name.given != NULL);
  2257.       fprintf (stderr, "%s", mapelt->info.name.given);
  2258.     }
  2259.   fprintf (stderr, "\n");
  2260. }
  2261.  
  2262. void
  2263. perror_with_name (name)
  2264.      char *name;
  2265. {
  2266.   extern int errno, sys_nerr;
  2267.   extern char *sys_errlist[];
  2268.   char *s;
  2269.  
  2270.   if (errno < sys_nerr)
  2271.     s = concat ("", sys_errlist[errno], " for %s");
  2272.   else
  2273.     s = "unknown error for %s";
  2274.   error (s, name);
  2275. }
  2276.  
  2277. void
  2278. pfatal_with_name (name)
  2279.      char *name;
  2280. {
  2281.   extern int errno, sys_nerr;
  2282.   extern char *sys_errlist[];
  2283.   char *s;
  2284.  
  2285.   if (errno < sys_nerr)
  2286.     s = concat ("", sys_errlist[errno], " for %s");
  2287.   else
  2288.     s = "cannot open %s";
  2289.   fatal (s, name);
  2290. }
  2291.  
  2292. /* Return a newly-allocated string whose contents
  2293.    concatenate those of S1, S2, and S3.  */
  2294.  
  2295. char *
  2296. concat (s1, s2, s3)
  2297.      char *s1, *s2, *s3;
  2298. {
  2299.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  2300.   char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  2301.  
  2302.   strcpy (result, s1);
  2303.   strcpy (result + len1, s2);
  2304.   strcpy (result + len1 + len2, s3);
  2305.   *(result + len1 + len2 + len3) = 0;
  2306.  
  2307.   return result;
  2308. }
  2309.  
  2310. /* Like malloc but get fatal error if memory is exhausted.  */
  2311.  
  2312. char *
  2313. xmalloc (size)
  2314.      unsigned int size;
  2315. {
  2316.   extern char *malloc ();
  2317.   char *result = malloc (size);
  2318.   if (result == 0)
  2319.     fatal ("virtual memory exhausted", 0);
  2320.   return result;
  2321. }
  2322.  
  2323. char *
  2324. xrealloc (ptr, size)
  2325.      char *ptr;
  2326.      unsigned int size;
  2327. {
  2328.   extern char *realloc ();
  2329.   char *result = realloc (ptr, size);
  2330.   if (result == 0)
  2331.     fatal ("virtual memory exhausted");
  2332.   return result;
  2333. }
  2334.  
  2335.  
  2336. /* Operations on member_names: */
  2337.  
  2338. /* Convert USER_NAME, possibly a path, into the name that goes into
  2339.    the archive header.  This involves stripping off leading path
  2340.    information and truncating the final name according to the desired
  2341.    rules.  The caller is responsible for freeing the returned string. */
  2342.  
  2343. char *
  2344. user_to_header(user_name)
  2345.      char *user_name;
  2346. {
  2347.   int namelen;
  2348.   struct ar_hdr dummy_hdr;
  2349.   char *result;
  2350.   char *tmp;
  2351.   char *file_name;        /* user name after removing initial path */
  2352.  
  2353.   /* Make a clean copy of the user name.  Bump the pointer past any
  2354.      leading path information.  */
  2355.  
  2356.   tmp = concat(user_name, "", "");
  2357.  
  2358.   user_name = rindex(tmp, '/');
  2359.   user_name = (user_name ? user_name + 1 : tmp);
  2360.  
  2361.   /* Save a copy of the file name, in case we need it for an error
  2362.      message later. */
  2363.   file_name = concat (user_name, "", "");
  2364.  
  2365.   /* Truncate the name to fit the ar header size. */
  2366.   namelen = strlen (user_name);
  2367.   if (namelen >= sizeof (dummy_hdr.ar_name))
  2368.     {
  2369.       if (gnu_truncation
  2370.       && user_name[namelen - 2] == '.'
  2371.       && user_name[namelen - 1] == 'o')
  2372.     {
  2373.       user_name[sizeof (dummy_hdr.ar_name) - 3] = '.';
  2374.       user_name[sizeof (dummy_hdr.ar_name) - 2] = 'o';
  2375.     }
  2376.       user_name[sizeof (dummy_hdr.ar_name) - 1] = '\0';
  2377.       error ("Using member name `%s' for filename `%s'", user_name, file_name);
  2378.     }
  2379.  
  2380.   /* Now make a fresh copy to return to the user. */
  2381.   result = concat (user_name, "", "");
  2382.  
  2383.   free (tmp);
  2384.   free (file_name);
  2385.   return result;
  2386. }
  2387.  
  2388. /* Return non-zero if the member names match.  As a side effect, 
  2389.    propogates user names.  This side-effect is important for, e.g.,
  2390.    extracting named members.  */ 
  2391.  
  2392. int
  2393. name_match(name1, name2)
  2394.      struct member_name *name1, *name2;
  2395. {
  2396.   if (strcmp(name1->stored, name2->stored) !=0)
  2397.     return 0;
  2398.  
  2399.   /* They match. */
  2400.   if (name1->given && !name2->given)
  2401.     name2->given = concat (name1->given, "", "");
  2402.   if (name2->given && !name1->given)
  2403.     name1->given = concat (name2->given, "", "");
  2404.  
  2405.   return 1;
  2406. }
  2407.  
  2408. /* Return an array of member names, from an argv-type array of user 
  2409.    names. */
  2410.  
  2411. struct member_name *
  2412. make_file_args (argvp, num_files)
  2413.      char **argvp;
  2414.      int num_files;            /* number of elements in argvp array */
  2415. {
  2416.   struct member_name *result, *name;
  2417.  
  2418.   result = (struct member_name *)xmalloc ((num_files + 1) *
  2419.                       sizeof (struct member_name));
  2420.   for (name = result; name < result + num_files; ++name, ++argvp)
  2421.     init_name (name, *argvp);
  2422.  
  2423.   name->given = NULL;
  2424.   name->stored = NULL;
  2425.  
  2426.   return result;
  2427. }
  2428.  
  2429. /* Initialize a member_name.  The caller is responsible for eventually
  2430.    freeing the allocated strings.  */
  2431.  
  2432. void
  2433. init_name (name_ptr, user_name)
  2434.      struct member_name *name_ptr;
  2435.      char *user_name;
  2436. {
  2437.   name_ptr->given = concat (user_name, "", "");
  2438.   name_ptr->stored = user_to_header (user_name);
  2439. }
  2440.  
  2441. void
  2442. free_name_strings (name_ptr)
  2443.      struct member_name *name_ptr;
  2444. {
  2445.   if (name_ptr->given)
  2446.     free (name_ptr->given);
  2447.   if (name_ptr->stored)
  2448.     free (name_ptr->stored);
  2449.   name_ptr->given = name_ptr->stored = NULL;
  2450. }
  2451.  
  2452. /* Methods for managing mapelt's. */
  2453.  
  2454. /* Initialize a map element: make sure the name is empty. */
  2455.  
  2456. void
  2457. init_elt (elt)
  2458.      struct mapelt *elt;
  2459. {
  2460.   elt->info.name.stored = elt->info.name.given = NULL;
  2461. }
  2462.  
  2463. /* Mark a map element for deletion by making the name empty.
  2464.    XXX - leaks some memory here. */
  2465.  
  2466. void
  2467. mark_as_deleted (elt)
  2468.      struct mapelt *elt;
  2469. {
  2470.   elt->info.name.stored = elt->info.name.given = NULL;
  2471. }
  2472.  
  2473. int
  2474. marked_for_deletion (elt)
  2475.      struct mapelt *elt;
  2476. {
  2477.   return Empty_Name(&elt->info.name);
  2478. }
  2479.